//
//  FMDownLoader.m
//  FMDownLoad
//
//  Created by apple on 17/3/20.
//  Copyright © 2017年 apple. All rights reserved.
//

#import "FMDownLoader.h"
#import "FMFileTool.h"
#import "NSString+MD5.h"


#define kCache    NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject
#define kTmp NSTemporaryDirectory()


@interface FMDownLoader ()<NSURLSessionDataDelegate>
{
    long long _tmpFileSize;
    long long _totalFileSize;

}


//@property (nonatomic, copy) NSString *downLoadingFilePath;
//
//@property (nonatomic, copy) NSString *downLoadedFilePath;

@property (nonatomic, strong) NSURLSession *session;

@property (nonatomic, strong) NSOutputStream *stream;

@property (nonatomic, weak) NSURLSessionDataTask *dataTask;

@property (nonatomic, weak) NSURL *url;

@property (nonatomic, copy) NSString *cacheFilePath;

@property (nonatomic, copy) NSString *tmpFilePath;


@end

@implementation FMDownLoader


- (void)downLoadedWithUrl:(NSURL *)url downLoadInfoTypeBlock:(DownLoadInfoTypeBlock)downLoadInfoTypeBlock successBlock:(DownLoadSuccessBlock)successBlock failBlock:(DownLoadFailTypeBlock)failBlock{
    
    self.downLoadInfoTypeBlock = downLoadInfoTypeBlock;
    self.successBlock = successBlock;
    self.failedBlock = failBlock;
    [self downLoadedWithUrl:url];
    
}


- (void)downLoadedWithUrl:(NSURL *)url{
    //下载文件存储机制
    //1.下载中的话 tmp+ (url+ md5)
    //2.下载完成 cacel +url.lastPathComponent
    self.url = url;
    self.cacheFilePath = [kCache stringByAppendingPathComponent:url.lastPathComponent];
    self.tmpFilePath = [kTmp stringByAppendingPathComponent:[url.absoluteString md5Str]];
    
    if ([FMFileTool fileExistsAtPath:self.cacheFilePath]) {
        NSLog(@"已经下载完成， 直接进行处理");
        if (self.downLoadInfoTypeBlock) {
            self.downLoadInfoTypeBlock([FMFileTool fileSizeAtFilePah:self.cacheFilePath]);
        }
        if (self.successBlock) {
            self.successBlock(self.cacheFilePath);
        }
        self.state = FMDownLoaderStateSuccess;
        return ;
    }
    
    //容错处理
    if ([url isEqual:self.dataTask.originalRequest.URL]) {
        if (self.state == FMDownLoaderStatePause) {
            [self resume];
            return ;
        }
        if (self.state == FMDownLoaderStateDowning) {
            return ;
        }
    }
    
    //走到这一步 说明url不一样 要先清掉
    [self cancel];
    _tmpFileSize = [FMFileTool fileSizeAtFilePah:self.tmpFilePath];
    NSLog(@"----%zd", _tmpFileSize);
    [self downLoadedWithUrl:url withOffset:_tmpFileSize];
    
}

+ (NSString *)downLoadedFileWithURL: (NSURL *)url{
    
    NSString *filePath = [kCache stringByAppendingPathComponent:url.lastPathComponent];
    if ([FMFileTool fileExistsAtPath:filePath]) {
        return filePath;
    }
    return nil;
}

+ (long long)tmpCacheSizeWithURL: (NSURL *)url{
    
    NSString *md5 = [url.absoluteString md5Str];
    NSString *tmpFilePath = [kTmp stringByAppendingPathComponent:md5];
    return [FMFileTool fileSizeAtFilePah:tmpFilePath];
}

+ (void)clearCacheWithURL: (NSURL *)url{
    NSString *filePath = [self downLoadedFileWithURL:url];
    [FMFileTool removeFlieAtPath:filePath];
}


- (void)pause{
    if (self.state == FMDownLoaderStateDowning) {
        [self.dataTask suspend];
        self.state = FMDownLoaderStatePause;
    }

}

- (void)resume{
    if (self.state == FMDownLoaderStatePause) {
        [self.dataTask resume];
        self.state = FMDownLoaderStateDowning;
    }
}

- (void)cancel{
    [self.session invalidateAndCancel];
    _tmpFileSize = 0;
    self.session = nil;

}

- (void)cancelAndClean{
    [self cancel];
    [FMFileTool removeFlieAtPath:self.tmpFilePath];

}

- (void)downLoadedWithUrl:(NSURL *)url withOffset:(long long)offset{
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:0];
    [request setValue:[NSString stringWithFormat:@"bytes=%lld-", offset] forHTTPHeaderField:@"Range"];
      NSURLSessionDataTask *dataTask =  [self.session dataTaskWithRequest:request];
    self.dataTask = dataTask;
    [self.dataTask resume];
}

#pragma mark---
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSHTTPURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler{
    
     //"Accept-Ranges" = bytes;
     //Connection = close;
     //"Content-Length" = 21574062;
     //"Content-Range" = "bytes 0-21574061/21574062";
    // "Content-Type" = ".dmg";
    // Date = "Wed, 22 Mar 2017 01:10:42 GMT";
    // Etag = "\"05f10628d1dd21:23ca\"";
    // "Last-Modified" = "Mon, 03 Oct 2016 15:47:02 GMT";
    // Server = "Microsoft-IIS/6.0";
 
    NSLog(@"----response = %@", response);
    NSDictionary *infoDic = response.allHeaderFields;
    _totalFileSize = [[infoDic[@"Content-Range"] componentsSeparatedByString:@"/"].lastObject longLongValue];
    if (self.downLoadInfoTypeBlock) {
        self.downLoadInfoTypeBlock(_totalFileSize);
    }
    if (_tmpFileSize < _totalFileSize) {
        //completionHandler(NSURLSessionResponseAllow);

    }else if (_tmpFileSize == _totalFileSize){
        NSLog(@"下载完成 ");
        if (self.successBlock) {
            self.successBlock(self.cacheFilePath);
        }
        [FMFileTool moveFromPath:self.tmpFilePath toPath:self.cacheFilePath];
        self.state = FMDownLoaderStateSuccess;
        completionHandler(NSURLSessionResponseCancel);
        return ;
    }else{
        [FMFileTool removeFlieAtPath:self.tmpFilePath];
        completionHandler(NSURLSessionResponseCancel);
        [self downLoadedWithUrl:response.URL];
        return ;
    }
    
//    if (self.messageBlock) {
//        self.messageBlock(_totalFileSize, self.downLoadedFilePath);
//    }
    self.state = FMDownLoaderStateDowning;
    self.stream = [NSOutputStream outputStreamToFileAtPath:self.tmpFilePath append:YES];
    [self.stream open];
    //这个放在上面会引起数据丢失一部分 坑爹
    completionHandler(NSURLSessionResponseAllow);


}

- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data{
    _tmpFileSize += data.length;
    [self.stream write:data.bytes maxLength:data.length];
    

    self.progress = 1.0 * _tmpFileSize / _totalFileSize;
    NSLog(@"正在下载数据");
}

- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error{
    
    [self.stream close];
    self.stream = nil;
    
    if (error == nil) {
        if (_tmpFileSize == _totalFileSize) {
            //下载完成 移动到downLoaded文件路径下
            NSLog(@"下载完成");
            [FMFileTool moveFromPath:self.tmpFilePath toPath:self.cacheFilePath];
            self.state = FMDownLoaderStateSuccess;
            if (self.successBlock) {
                self.successBlock(self.cacheFilePath);
            }
        }
    }else{
        self.state = FMDownLoaderStateFailed;
        NSLog(@"----错误 = %@, %@", error,error.localizedDescription);
        if (self.failedBlock) {
            self.failedBlock(error.localizedDescription);
        }
    }
}


#pragma mark----set get
- (NSString *)downLoadedPath{
    NSString *filePath = [kCache stringByAppendingPathComponent:@"downLoader/downLoaded"];
    BOOL result = [FMFileTool createFilePathIfNotExist:filePath];
    if (result) {
        return filePath;
    }
    return @"";
}

- (NSString *)downLoadingPath{
    NSString *filePath = [kCache stringByAppendingPathComponent:@"downLoader/downLoading"];
    BOOL result = [FMFileTool createFilePathIfNotExist:filePath];
    if (result) {
        return filePath;
    }
    return @"";
}

- (NSURLSession *)session{
    if (!_session) {
        _session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue new]];
    }
    return _session;
}

- (void)setState:(FMDownLoaderState)state{
    if (_state == state) {
        return ;
    }
    _state = state;
    if (self.stateChangeBlock) {
        self.stateChangeBlock(state);
    }
    
    [[NSNotificationCenter defaultCenter] postNotificationName:kDownLoadURLOrStateChangeNotification object:nil userInfo:@{@"downLoadURL" : self.url, @"downLoadState" : @(self.state)}];
    
}

- (void)setProgress:(float)progress{
    _progress = progress;
    if (self.progressBlock) {
        self.progressBlock(1.0 * _tmpFileSize / _totalFileSize);
    }
}

@end
